#ifndef __LINUX_IRQ_DOMAIN_H__
#define __LINUX_IRQ_DOMAIN_H__

#include "linux/irqhandler.h"
#include "linux/radix-tree.h"
#include "linux/irq.h"
#include "linux/of.h"
#include "linux/list.h"
#include "linux/of_irq.h"

struct irq_domain;
struct irq_data;
struct irq_chip;

struct irq_domain_ops
{
    int (*match)(struct irq_domain *d, struct device_node *node);
    int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
    void (*unmap)(struct irq_domain *d, unsigned int virq);
    int (*xlate)(struct irq_domain *d, struct device_node *node,
                 uint32_t *intspec, unsigned int intsize,
                 unsigned long *out_hwirq, unsigned int *out_type);

    int (*alloc)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *arg);
    void (*free)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs);
    void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
    void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
};

struct irq_domain
{
    struct list_head link;
     char *name;
     struct irq_domain_ops *ops;
    void *host_data;
    unsigned int flags;

    struct device_node *of_node;

    struct irq_domain *parent;

    irq_hw_number_t hwirq_max;
    unsigned int revmap_direct_max_irq;
    unsigned int revmap_size;
    struct radix_tree_root revmap_tree;
    unsigned int linear_revmap[];
};

enum
{
    /* Irq domain is hierarchical */
    IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0),

    /* Core calls alloc/free recursive through the domain hierarchy. */
    IRQ_DOMAIN_FLAG_AUTO_RECURSIVE = (1 << 1),

    /*
     * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
     * for implementation specific purposes and ignored by the
     * core code.
     */
    IRQ_DOMAIN_FLAG_NONCORE = (1 << 16),
};

extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, unsigned int virq);
extern unsigned int irq_find_mapping(struct irq_domain *domain, irq_hw_number_t hwirq);
extern struct irq_domain *irq_find_host(struct device_node *node);
extern void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, irq_hw_number_t hwirq_base, int count);

struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
                                    irq_hw_number_t hwirq_max, int direct_max,
                                     struct irq_domain_ops *ops,
                                    void *host_data);
extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
                                irq_hw_number_t hwirq, struct irq_chip *chip,
                                void *chip_data, irq_flow_handler_t handler,
                                void *handler_data, char *handler_name);

static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
                                                       unsigned int size,
                                                        struct irq_domain_ops *ops,
                                                       void *host_data)
{
    return __irq_domain_add(of_node, size, size, 0, ops, host_data);
}

static inline struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
                                         unsigned int size,
                                         unsigned int first_irq,
                                         irq_hw_number_t first_hwirq,
                                          struct irq_domain_ops *ops,
                                         void *host_data)
{
    struct irq_domain *domain;

    domain = __irq_domain_add(of_node, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
    if (domain)
        irq_domain_associate_many(domain, first_irq, first_hwirq, size);

    return domain;
}


extern  struct irq_domain_ops irq_domain_simple_ops;

#endif

